"""
Новая модификация:
- собирает ссылки на вакансии и вставляет в таблицу job_vacant
- удаляет старые ссылки по архиву вакансий job_s_ref
- собирает контактную информацию по вакансиям
- удаляет дублирование организаций
- сливает ссылки в общую таблицу
"""

import sys
import logging                                                                  # запись логов
import re                                                                       # регулярные выражения
import sqlite3

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

sys.path.append('c:\PyLib')
from ConnSQL import *
from WebKit import *

const_dict = {'login': 'http://joblab.ru/',
              'page':  'http://joblab.ru/search_vacancy.php?srregion=63&page={}&submit=1',
              'pref':  'http://www.superjob',
              'cookies': 'joblab_cookies.txt'}
for key, value in const_dict.items():                                           # динамическое создание переменных
    globals()[key] = value

    
def no_space(line):
    return ''.join(c for c in line if ord(c) >= 32)
    

def cookies_load():
    if os.path.exists(cookies):                                                 # если cookies уже сохранены
        f = open(cookies, 'r')                                                  # Загузка куков из файла
        allC = tuple(cooky for li in f                                          # выражение итератор
            for cooky in QNetworkCookie.parseCookies(li.rstrip()))
        if allC:
            web.Сookies.setAllCookies(allC)
        f.close()




def btn_login_click():                                                          #
    """
    Cтраница регистрации пользователя.
    Пользователь должен залогонится. После этого необходимо сохранить куки.
    """
    url = const_dict['login']
    web.get(url)

    btn_login.setEnabled(False)


def btn_collect_ref_click():
    """
    Загружает куки.
    Собирает ссылки на вакансии с сайта и вставляет в таблицу vacant.
    """
    cookies_load()# грузим куки

    query = conn.cursor()                                                       # курсор SQLite3
    query.execute("CREATE TABLE IF NOT EXISTS vacant "                          # создаем таблицу vacant
        "(url TEXT DEFAULT '', org TEXT DEFAULT '',"
        "face TEXT DEFAULT '', phone TEXT DEFAULT '');")
    query.executescript("DELETE FROM vacant; VACUUM;")                          # очистить рабочую таблицу и схлопуть базу
    
    pattern_page = re.compile('<span class="current">([\d]+?)</span>')                    # re текущая страница
    pattern_ref = re.compile('VacancyListElement_position_wr.+?href="(.+?)" class=',re.S)             # re ссылка на вакансию

    n = 1                                                                       # начинаем с первой страницы
    while 1:                                                                    # бесконечный цикл
        url = page.format(n)                                                     # сформировать URL очередной страницы
        line.setText('{}'.format(url))                                          # показать загружаемый URL
        web.get(url)                                                            # загрузить страницу
        m = pattern_page.search(web.html)                                       # ищем номер загруженной страницы
        if m:                                                                   # найден
            page_curr = int(m.group(1))                                         # взять номер страницы
            if n == page_curr:                                                  # сравнить реальный номер с требуемым номером
                list_url = pattern_ref.findall(web.html)                        # совпало. находим все URL ссылки на вакансии
                values = []                                                     # преобразуем список
                for url in list_url:                                            # найденных вакансий
                    values.append('("' + url + '")')    #
                sql = ('INSERT INTO vacant (url) VALUES {};'.                   # в INSERT запрос
                       format(','.join(values)))                                #
                try:                                                            # обработка исключения
                    query.execute(sql)                                          # вставляем ссылки в таблицу vacant
                except sqlite3.Error as e:
                    logging.error('btn_collect_ref_click: {} {}'.
                        format( e.args[0],sql))
                    btn_quit_click()
                else:
                    conn.commit()                                               # конец транзакции
            else:                                                               # иначе, если номер загруженной страницы
                break                                                           # не совпал, выходим из бесконечного цикла
            n += 1
        else:                                                                   # если не удалось найти номер страницы
            logging.error("Не удалось прочитать номер страницы на: {}".
                format(url))
            query.close()
            btn_quit_click()                                                    # расцениваем как тотальную ошибку

    query.close()

    btn_collect_ref.setEnabled(False)                                           # гасим кнопку


def btn_del_old_ref_сlick():
    """
    Удаляем обработанные ссылки.
    """
    query = conn.cursor()                                                       # курсор SQLite3
    query.execute("CREATE TABLE IF NOT EXISTS ref (url TEXT DEFAULT '');")      # создаем таблицу обработанных ссылок
    sql = ("DELETE FROM vacant WHERE ROWID IN "                                 # удалить из vacant сысылки сохраненные в ref
        "(SELECT v.ROWID FROM vacant as v, ref as r WHERE v.url= r.url);")
    try:
        query.execute(sql)                                                      # удаляем ссылки
    except sqlite3.Error as e:
        logging.error('btn_collect_ref_click: {} {}'.format( e.args[0],sql))
        btn_quit_click()
    else:
        conn.commit()
    query.close()

    btn_del_old_ref.setEnabled(False)


def btn_load_vacant_click():
    """
    Собирает описание вакансий.
    """
    cookies_load()# грузим куки
    pattern_face = re.compile('<span class="h_font_medium">(.+?)</span><br>')                    # контактоное лицо
    pattern_org = re.compile('<div class="VacancyView_location">'
        '(.+?)<span class="h_color_gray VacancyView_town">',re.S)                       # название компании
    pattern_org2 = re.compile('>(.+?)<') # организация внутри html ссылки
    pattern_phone = re.compile('<div class="VacancyViewSendResume_phone">(.+?)</div>',re.S)                  # контактный телефон

    select = conn.cursor()                                                      # для обхода записей
    update = conn.cursor()                                                      # для обновления записей

    select.execute("SELECT count(*) FROM vacant;")                              # количество записей
    rec = select.fetchone()                                                     # в таблице vacant
    pb.setRange(0,rec[0])                                                       # инициализация индикатора процесса

    select.execute("SELECT ROWID, url FROM vacant;")                            # запрос по всем записям таблицы
    ind = 0                                                                     # текущее значение прогресс бара

    for id, ref in select:                                                      # текущая запись и ссылка
        line.setText('{}'.format(ref))                                          #
        web.get(ref)                                                            # загружаем страницу вакансии

        ind += 1
        pb.setValue(ind)                                                        # индикатор процесса

        face, org, phone = '','',''                                             # очищаем переменные
        m = pattern_face.search(web.html)                                       # ищем контактное лицо
        if m:
            face = m.group(1)                                                     # если найдено - 1-я группа
        m = pattern_org.search(web.html)                                        # ищем название организации
        if m:
            org = m.group(1)                                                     # если найдено - 1-я группа
            m = pattern_org2.search(org)#выделяем если название внутри html ссылки
            if m:# название было внутри ссылки
                org = m.group(1)
        m = pattern_phone.search(web.html)                                      # ищем контактный телефон
        if m:
            phone = no_space(m.group(1))                                                  # если найдено - 1-я группа

        sql = ("UPDATE vacant SET face = '{}',org = ?,"                         #
            "phone = '{}' WHERE ROWID = {}".
            format(face, phone, id))
        try:
            update.execute(sql, (org,))                                         # обновляем запись
        except sqlite3.Error as e:
            logging.error('btn_load_vacant_click: {} {}'.format( e.args[0],sql))
            btn_quit_click()
        else:
            conn.commit()

    select.close()
    update.close()

    btn_load_vacant.setEnabled(False)


def btn_clean_org_click():
    """
    Удаляет дубли и запрещенные организации.
    """
    query = conn.cursor()                                                       
    
    query.execute("DELETE FROM vacant WHERE ROWID NOT IN ("                    # удалить дубли по имени организации
        "SELECT MIN(ROWID) FROM vacant GROUP BY org);")
    conn.commit()

    query.execute(                                                              # создаем таблицу организаций для бана
        "CREATE TABLE IF NOT EXISTS org (name TEXT DEFAULT '');")
    sql = ("DELETE FROM vacant WHERE ROWID IN "                                 # баним организации
        "(SELECT v.ROWID FROM vacant as v, org as r WHERE v.org= r.name);")
    query.execute(sql)
    conn.commit()

    btn_clean_org.setEnabled(False)


def btn_merge_vacant_click():
    """
    Слияние вакансий в твблицу distrib
    """
    conn_out = sqlite3.connect("distrib.db")                                    # глобальная БД
    out = conn_out.cursor()                                                     
    out.execute("CREATE TABLE IF NOT EXISTS vacant "                          # создаем таблицу vacant
        "(url TEXT DEFAULT '',"                                                 # в глобальной базе
        " org TEXT DEFAULT '', org_find TEXT DEFAULT '',"
        " org_CRM TEXT DEFAULT '',face TEXT DEFAULT '',"
        " phone TEXT DEFAULT '', phone_find TEXT DEFAULT '',"
        " curator TEXT DEFAULT '');")

    query = conn.cursor()                                                         # локальная БД
    query.execute("SELECT * FROM vacant;")                                        # все записи из рабочей таблицы
    arr = query.fetchall()                                                        # загружаем в массив
    sql = "INSERT INTO vacant (url,  phone, face, org) VALUES (?,?,?,?);"       # запрос с подстановкой
    try:
        out.executemany(sql, arr)                                               # повторять для каждой записи из массива
    except sqlite3.Error as e:
        logging.error('btn_add_ref_click: {} {}'.format( e.args[0],sql))
        btn_quit_click()
    else:
        conn_out.commit()                                                       # Завершаем транзакцию
    query.close()                                                                 # закрыть курсоры
    out.close()                                                                 # закрыть курсоры
    conn_out.close()                                                            # закрыть соединение с удалённой базой

    btn_merge_vacant.setEnabled(False)


def btn_add_ref_click():
    """
    Ссылки на вакансии из рабочей таблицы добавляются в архив ссылок
    """
    query = conn.cursor()
    sql = ("INSERT INTO ref (url) SELECT url FROM vacant;")                     # сливаем ссылки в таблицу ref
    try:
        query.execute(sql)
    except sqlite3.Error as e:
        logging.error('btn_add_ref_click: {} {}'.format( e.args[0],sql))
        btn_quit_click()
    else:
        conn.commit()

    btn_add_ref.setEnabled(False)


def btn_quit_click():
    """
    Сохранение куков в файле и выход.
    """
    f = open(cookies, 'wb')
    allC = web.Сookies.allCookies()
    for c in allC:
        f.write(c.toRawForm()+"\n")
    f.close()
    conn.close()
    quit()


if __name__ == '__main__':                                                      # ОСНОВНОЙ ЦИКЛ
    app = QApplication(sys.argv)

    logging.basicConfig(filename='log.txt',level=logging.DEBUG)                 # log file
    
    conn = sqlite3.connect("sjob.db")                                            # Имя в соответствии с именем модуля
    
    window = QWidget()
    window.setWindowTitle("sjob.ru")
    window.resize(1000, 700)

    web = Browser()

    vbox_btn = QVBoxLayout()                                                    # вертикальный контейнер кнопок
    vbox_r = QVBoxLayout()                                                      # вертикальный контейнер справа

    btn_login = QPushButton("ЛОГИН")
    btn_login.clicked.connect(btn_login_click)
    vbox_btn.addWidget(btn_login)

    btn_collect_ref = QPushButton("Собрать ссылки")
    btn_collect_ref.clicked.connect(btn_collect_ref_click)
    vbox_btn.addWidget(btn_collect_ref)

    btn_del_old_ref = QPushButton("Очистить ссылки")
    btn_del_old_ref.clicked.connect(btn_del_old_ref_сlick)
    vbox_btn.addWidget(btn_del_old_ref)

    btn_load_vacant = QPushButton("Собрать вакансии")
    vbox_btn.addWidget(btn_load_vacant)
    btn_load_vacant.clicked.connect(btn_load_vacant_click)

    btn_clean_org = QPushButton("Очистить организации")
    btn_clean_org.clicked.connect(btn_clean_org_click)
    vbox_btn.addWidget(btn_clean_org)

    btn_merge_vacant = QPushButton("Слить организации")
    btn_merge_vacant.clicked.connect(btn_merge_vacant_click)
    vbox_btn.addWidget(btn_merge_vacant)

    btn_add_ref = QPushButton("Запомнить ссылки")
    btn_add_ref.clicked.connect(btn_add_ref_click)
    vbox_btn.addWidget(btn_add_ref)

    btn_quit = QPushButton("ВЫХОД")
    btn_quit.clicked.connect(btn_quit_click)
    vbox_btn.addWidget(btn_quit)

    pb = QProgressBar()
    info = QTextEdit()

    vbox_r.addWidget(pb)
    vbox_r.addWidget(info)

    # горизонтальный Layout
    hbox = QHBoxLayout()
    hbox.addLayout(vbox_btn)
    hbox.addLayout(vbox_r)
    line = QLineEdit()

    vbox2 = QVBoxLayout()
    vbox2.addWidget(line)
    vbox2.addWidget(web)
    vbox2.addLayout(hbox)

    window.setLayout(vbox2)
    window.show()

    sys.exit(app.exec_())
